package com.spzx.common.rabbit.service;

import com.alibaba.fastjson2.JSON;
import com.spzx.common.core.utils.uuid.UUID;
import com.spzx.common.rabbit.entity.GuiguCorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * 生产者端：即发送消息的一端。
 */
@Component
public class RabbitService {

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    RedisTemplate redisTemplate;

    /**
     * 发送消息
     *
     * @param exchange   交换机名称
     * @param routingKey 路由key
     * @param message    消息
     * @return 发送消息是否成功
     */
//    public boolean sendMsg(String exchange,String routingKey,Object message){
//        rabbitTemplate.convertAndSend(exchange,routingKey,message);
//        return true;
//    }
    public boolean sendMsg(String exchange, String routingKey, Object message) {
        //关联数据对象：用于消息重复发送。
        GuiguCorrelationData correlationData = new GuiguCorrelationData();
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        correlationData.setId(uuid);
        correlationData.setMessage(message);
        correlationData.setExchange(exchange);
        correlationData.setRoutingKey(routingKey);
        //correlationData.setRetryCount(0);


        //将关联数据存储到redis中。为什么？因为回退回调函数，它不能直接获取返回的关联数据，
        // 需要根据关联数据的id从缓存中获取关联数据，再进行消息重复。
        redisTemplate.opsForValue().set(uuid, JSON.toJSONString(correlationData), 5, TimeUnit.MINUTES);


        //发送消息同时，把关联数据也发送。回退时需要把关联数据也进行回退，根据关联数据就可以进行消息重复。
        rabbitTemplate.convertAndSend(exchange, routingKey, message, correlationData);

        //这行代码放在发消息后，会导致：消息发送马上执行回退，而此时，携带关联数据可能还没有存储到缓存中。执行回退函数从缓存中获取数据就是空，报空指针。
        //redisTemplate.opsForValue().set(uuid, JSON.toJSONString(correlationData),5, TimeUnit.MINUTES);

        return true;
    }

    public boolean sendDelayMessage(String exchangeDelay, String routingKey, String message, int delayTime) {
        //关联数据对象：用于消息重复发送。
        GuiguCorrelationData correlationData = new GuiguCorrelationData();
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        correlationData.setId(uuid);
        correlationData.setMessage(message);
        correlationData.setExchange(exchangeDelay);
        correlationData.setRoutingKey(routingKey);
        correlationData.setRetryCount(0);
        correlationData.setDelay(true); //延迟消息
        correlationData.setDelayTime(delayTime);


        //将关联数据存储到redis中。为什么？因为回退回调函数，它不能直接获取返回的关联数据，
        // 需要根据关联数据的id从缓存中获取关联数据，再进行消息重复。
        redisTemplate.opsForValue().set(uuid, JSON.toJSONString(correlationData), 5, TimeUnit.MINUTES);


        //发送消息同时，把关联数据也发送。回退时需要把关联数据也进行回退，根据关联数据就可以进行消息重复。
        rabbitTemplate.convertAndSend(exchangeDelay, routingKey, message, messageObj -> {
            messageObj.getMessageProperties().setDelay(delayTime * 1000); //单位毫秒
            return messageObj;
        }, correlationData);

        return true;
    }
}
